﻿using Newtonsoft.Json; 
using SHKF.B2C.WanLiNiu.Model;
using SHKF.B2C.WanLiNiu.Model.Inter.GoodsAdd;
using SHKF.B2C.WanLiNiu.Model.Inter.InventorySyn;
using SHKF.B2C.WanLiNiu.Model.Inter.OpenTradeListTrades;
using SHKF.B2C.WanLiNiu.Model.Inter.StorageQuery;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Web;

namespace SHKF.B2C.WanLiNiu.Network
{
    public class HttpClientWLN : HttpClient
    {
        public string app_key = "3223519356";
        public string app_secret = "726c8802a82f4d39caaf0ddcb3b1da6a";

        private string urlGoodAdd = "/erp/goods/add/item";   //推送给万里牛ERP系统商品
        private string urlGoodUpdate = "/erp/goods/update/item";        //修改万里牛ERP系统商品信息,对外开放;
        private string urlStorageQuery = "/erp/base/storage/query";     //查询仓库信息
        private string urlInventorySyn = "/erp/open/inventory/syn";     //同步库存
        private string urlOrderList = "/erp/opentrade/list/trades";      //查询订单

        public HttpClientWLN()
        {
            base.BaseAddress = new Uri("https://open-api.hupun.com/api");
        }

        public async Task<GoodDto> GoodAdd(GoodAddParam data)
        { 
            GoodDto dto = await this.Post<GoodDto>(this.urlGoodAdd, data); 
            return dto;
        }
 
        public async Task<GoodDto> GoodUpdate(GoodUpdateParam data)
        {
            GoodDto dto = await this.Post<GoodDto>(this.urlGoodUpdate, data);
            return dto;
        }
         
        public async Task<StorageDto> StorageQuery(int page_no, int page_size)
        {
            Dictionary<string, object> data = new Dictionary<string, object>();
            data.Add("page_no", page_no);
            data.Add("page_size", page_size); 

            StorageDto dto = await this.Get<StorageDto>(urlStorageQuery, data); 
            return dto;
        }

        public async Task<InventorySynDto> InventorySyn(InventorySynParam data)
        {
            InventorySynDto dto = await this.Post<InventorySynDto>(this.urlInventorySyn, data);
            return dto;
        }

        public async Task<OpenTradeListDto> OrderList(Dictionary<string, object> data)
        {
            //OrderQueryParam data
            OpenTradeListDto dto = await this.Get<OpenTradeListDto>(this.urlOrderList, data);
            return dto;
        }


        private async Task<T> Post<T>(string api, object data) where T : BaseDto, new()
        {
            string requestUri = base.BaseAddress.OriginalString + api;
            Hashtable ht = GetBaseParam();

            if (data != null)
            {
                PropertyInfo[] list = data.GetType().GetProperties();
                foreach (PropertyInfo propertyInfo in list)
                {
                    string name = propertyInfo.Name;
                    object value = propertyInfo.GetValue(data);

                    try
                    {
                        string json = JsonConvert.SerializeObject(value);
                        value = json;
                    }
                    catch
                    {

                    }
                    if( value != null)
                    {
                        ht.Add(name, value);
                    } 
                }
            }

             string sign = this.getSign(ht);  
            string text = this.getParamData(ht);
            text += "&_sign=" + sign;

            HttpContent content = new StringContent(text, Encoding.UTF8);
            content.Headers.ContentType = new MediaTypeHeaderValue("application/x-www-form-urlencoded");
            HttpResponseMessage httpResponseMessage = await base.PostAsync(requestUri, content);

            string str = await httpResponseMessage.Content.ReadAsStringAsync();
            if (httpResponseMessage.IsSuccessStatusCode)
            { 
                try
                {
                    T result = await httpResponseMessage.Content.ReadAsAsync<T>();
                    return result;
                }
                catch (Exception ex)
                {
                    T exInfo = new T();
                    exInfo.code = -1;
                    exInfo.message = ex.Message;
                    return exInfo;
                }

            }
            else
            { 
                BaseDto error = await httpResponseMessage.Content.ReadAsAsync<BaseDto>();
                T error2 = new T();
                error2.code = error.code;
                error2.message = error.message;
                return error2;
            }
        }

        private async Task<T> Get<T>(string api, Dictionary<string,object> data) where T : BaseDto, new()
        {
            string requestUri = base.BaseAddress.OriginalString + api;
            Hashtable ht = GetBaseParam();

            if (data != null)
            {
                foreach (var item in data)
                {
                    ht.Add(item.Key, item.Value);
                }
            }

            string sign = this.getSign(ht);
            string text = this.getParamData(ht);
            text += "&_sign=" + sign;

            //requestUri += "?" + text;

            HttpContent content = new StringContent(text, Encoding.UTF8);
            content.Headers.ContentType = new MediaTypeHeaderValue("application/x-www-form-urlencoded");
            HttpResponseMessage httpResponseMessage = await base.PostAsync(requestUri, content);

            string str = await httpResponseMessage.Content.ReadAsStringAsync();
            if (httpResponseMessage.IsSuccessStatusCode)
            {
                try
                {
                    T result = await httpResponseMessage.Content.ReadAsAsync<T>();
                    return result;
                }
                catch (Exception ex)
                {
                    T exInfo = new T();
                    exInfo.code = -1;
                    exInfo.message = ex.Message;
                    return exInfo;
                }

            }
            else
            {
                BaseDto error = await httpResponseMessage.Content.ReadAsAsync<BaseDto>();
                T error2 = new T();
                error2.code = error.code;
                error2.message = error.message;
                return error2;
            }
        }

        private Hashtable GetBaseParam()
        {
            DateTime now = DateTime.Now;
            long time = DateTimeUtil.DateTimeToLongTimeStamp(now);
            Hashtable ht = new Hashtable();
            ht.Add("_app", this.app_key);
            ht.Add("_t", time);

            return ht;
        }


        private string getParamData(Hashtable ht)
        {
            string str = "";
            foreach (DictionaryEntry items in ht)
            {
                if (str != "")
                {
                    str += "&";
                }
                string key = items.Key.ToString(); 
                string value = UrlEncode(items.Value.ToString());
                str += $"{key}={value}"; 
            }

            return str;
        }

        private string getSign(Hashtable param)
        {
            ArrayList keys = new ArrayList(param.Keys);
            keys.Sort(); //按字母顺序进行排序
            string resultStr = "";
            foreach (string key in keys)
            {
                if (key != null && key != "")
                {
                    if (resultStr != "")
                    {
                        resultStr += "&";
                    }

                    string value = UrlEncode(param[key].ToString());
                    resultStr += $"{key}={value}"; 
                }
            }

            resultStr = app_secret + resultStr + app_secret;
            MD5 md5 = MD5.Create();
            byte[] rstRes = md5.ComputeHash(Encoding.UTF8.GetBytes(resultStr));
            string hex = BitConverter.ToString(rstRes, 0).Replace("-", string.Empty).ToUpper();
            return hex; 
        }

        public string UrlEncode(string str)
        {
            StringBuilder builder = new StringBuilder();
            foreach (char c in str)
            {
                if (HttpUtility.UrlEncode(c.ToString()).Length > 1)
                {
                    builder.Append(HttpUtility.UrlEncode(c.ToString()).ToUpper());
                }
                else
                {
                    builder.Append(c);
                }
            }
            return builder.ToString();
        }

    }
}
